#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <unistd.h>

#define BUFFER_SIZE 1024
#define PORT        8100

using namespace std;

int main() {
  int 
    _socket, 
    _bind,
    _listen, 
    _connection;
  
  char 
    //send_buffer[BUFFER_SIZE],
    recv_buffer[BUFFER_SIZE];
  
  struct sockaddr_in server, client;

  int 
    pid,
    bytes_recieved,
    sin_size = sizeof(struct sockaddr_in); // A constant to be used later


  // Create socket; use _socket as a handle for future reference
  _socket = socket(PF_UNIX, SOCK_STREAM, 0);
  
  if (_socket == -1) {
    perror("socket()");
    exit(1);
  }
  
  // Set up server-side address info in the appropriate sockaddr_in struct
  server.sin_family = PF_UNIX;
  server.sin_port = htons(PORT);
  server.sin_addr.s_addr = INADDR_ANY;
  bzero((char*)server.sin_zero, 8); // copy eight 0 bits into the sin_zero member of the sockaddr_in struct

  // Bind _socket to the port and address just set up in "server"
  _bind = bind(_socket, (struct sockaddr *)&server, sizeof(struct sockaddr));
  
  if (_bind == -1) {
    perror("bind()");
    exit(1);
  }
  
  // Begin listening, allowing 5 queued connections
  _listen = listen(_socket, 5);

  if (_listen == -1) {
    perror("listen()");
    exit(1);
  }
  
  cout << "Waiting for client on port PORT\n";

  fflush(stdout);

  while (1) {
    _connection = accept(_socket, (struct sockaddr *)&client, (socklen_t*)&sin_size);
    
    cout << "Connection to (" << inet_ntoa(client.sin_addr) << "," << ntohs(client.sin_port) << ") established.\n";
    
    pid = (int)fork();
    
    if (pid == 0) {
      while (1) {
	bytes_recieved = recv(_connection, recv_buffer, BUFFER_SIZE, 0);
	recv_buffer[bytes_recieved] = '\0';
	
	if (strcmp(recv_buffer, "q") == 0 || strcmp(recv_buffer, "Q") == 0) {
	  printf("Done. Exiting now.\n");
	  break;
	}
	else {
	  printf("Data recieved:  \"%s\"", recv_buffer);
	}
	fflush(stdout);
	send(_connection, "ack", strlen("ack"), 0);
      }
      close(_connection);
    }
  }
  
  return 0;
}
